import { FONT_5X5, FONT_5X5_SPACING } from "./font";
import {
  add,
  intersect,
  subtract,
  stack,
  thicken,
  wireFrame,
  clearPivot,
  flip,
  rotate,
  scale as scaleOperation,
  setPivot,
  mirror,
  getDimensions,
  getMaterialCost,
  normalizeAndUpdateBounds,
  getData,
  exportFromWorld,
  importToWorld,
  importToWorldAsync,
  copyConsoleCommand,
  copyJSON,
  erode,
  ErosionOptions,
  shell,
  decay,
  gradientReplace,
  sharpen,
  smooth,
  cloneToSurface,
  replaceAllBlocks,
  replaceBlocks,
  replaceByPattern,
  createSphere,
  createCylinder,
  createPyramid,
  createCuboid,
  createTorus,
  createPipe,
  createCapsule,
  createCone,
  createPrism,
  generateCatmullRomPath,
  generateStampTransformsOnPath,
} from "./modules";
import {
  CloneToSurfaceOptions,
  ConeOptions,
  CuboidOptions,
  CylinderOptions,
  FromPathOptions,
  FromPathWallOptions,
  PatternEntry,
  PatternMap,
  PrismOptions,
  PyramidOptions,
  SharpenOptions,
  SmoothOptions,
  SphereOptions,
} from "./options";
import { CompressedTerrainData, ReplacementMap, SchematicBlock } from "./types";

/**
 * 一个用于处理地形蓝图 (Schematic) 的类。
 * 通过创建一个实例来捕获一个区域的地形，然后可以使用链式方法对其进行修改（如旋转、翻转、替换方块），最后将其导入到世界中。
 * @example new TerrainSchematic(new GameBounds3(new GameVector3(0, 0, 0), new GameVector3(30, 64, 30))).rotate('y', 90).flip('x').import(new GameVector3(10, 20, 30));
 */
export default class TerrainSchematic {
  /** 存储当前蓝图的核心数据，但不包含图层字符串 */
  public data: Omit<CompressedTerrainData, "layers">;
  /** 内部使用的高效方块列表，用于所有编辑操作 */
  public schematicBlocks: SchematicBlock[] = [];
  /** 用于旋转和缩放的自定义轴心点，相对于 (0,0,0) 的局部坐标。如果为null，则使用几何中心。 */
  public pivot: GameVector3 | null = null;
  /** 蓝图的(0,0,0)点在世界坐标系中的位置 */
  public origin: GameVector3;

  /**
   * 创建一个新的 TerrainSchematic 实例。
   * 构造函数会立即调用 export 方法，扫描并存储给定边界内的地形数据。
   * @param bounds 定义了要捕获的初始地形区域的边界框。
   * @throws 如果提供的 `bounds` 不是 `GameBounds3` 的有效实例，则抛出错误。
   */
  constructor(bounds: GameBounds3) {
    if (!(bounds instanceof GameBounds3)) {
      throw new Error("边界框必须是一个GameBounds3实例");
    }
    // 初始化data结构
    this.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    this.origin = bounds.lo;
    this.export(bounds);
  }

  /**
   * 从一个已有的 `CompressedTerrainData` 对象创建一个新的 `TerrainSchematic` 实例。
   * 这个静态方法允许你加载一个之前保存的蓝图，而无需重新扫描世界。
   * @param data 从 `getData()` 获取或从文件/数据库加载的完整蓝图数据。
   * @returns 一个新的 `TerrainSchematic` 实例，包含了所提供的数据。
   */
  public static fromData(data: CompressedTerrainData): TerrainSchematic {
    // 使用 Object.create 来创建一个实例，而不触发构造函数中的 export
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;

    // 注入数据
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(data.bounds.lo.x, data.bounds.lo.y, data.bounds.lo.z),
        new GameVector3(data.bounds.hi.x, data.bounds.hi.y, data.bounds.hi.z)
      ),
      palette: data.palette,
    };
    schematic.origin = new GameVector3(
      data.bounds.lo.x,
      data.bounds.lo.y,
      data.bounds.lo.z
    );

    // 解析图层字符串为内部高效的方块列表
    schematic.schematicBlocks = [];
    data.layers.forEach((layerString, y) => {
      if (!layerString) {
        return;
      }
      const blocks = layerString.split(";");
      for (const blockStr of blocks) {
        const [x, z, p] = blockStr.split(",").map(Number);
        schematic.schematicBlocks.push({ x, y, z, p: p });
      }
    });

    // 创建后立即归一化，确保内部坐标从0开始，并设置正确的origin
    normalizeAndUpdateBounds(schematic);

    return schematic;
  }

  /**
   * 克隆当前的蓝图实例。
   * @returns 一个与当前实例完全一样但独立的新 `TerrainSchematic` 实例。
   */
  public clone(): TerrainSchematic {
    const newSchematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    newSchematic.data = {
      bounds: new GameBounds3(
        new GameVector3(
          this.data.bounds.lo.x,
          this.data.bounds.lo.y,
          this.data.bounds.lo.z
        ),
        new GameVector3(
          this.data.bounds.hi.x,
          this.data.bounds.hi.y,
          this.data.bounds.hi.z
        )
      ),
      palette: [...this.data.palette],
    };
    newSchematic.schematicBlocks = this.schematicBlocks.map((b) => ({ ...b }));
    newSchematic.pivot = this.pivot
      ? new GameVector3(this.pivot.x, this.pivot.y, this.pivot.z)
      : null;
    newSchematic.origin = new GameVector3(
      this.origin.x,
      this.origin.y,
      this.origin.z
    );
    return newSchematic;
  }

  /**
   * 根据给定的参数创建一个球体蓝图。
   * @param radius 球体的半径。
   * @param voxelId 用于构成球体的方块ID。
   * @param voxelRot 球体方块的旋转方向，默认为0。
   * @param options 其他选项，例如 `{ isHollow: true }` 来创建空心球体。
   * @returns 一个包含球体的全新 `TerrainSchematic` 实例。
   */
  public static fromSphere(
    radius: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: SphereOptions = {}
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createSphere(schematic, radius, voxelId, voxelRot, options);
  }

  /**
   * 根据给定的参数创建一个圆柱体蓝图。
   * @param radius 圆柱的半径。
   * @param height 圆柱的高度。
   * @param voxelId 用于构成圆柱的方块ID。
   * @param voxelRot 圆柱方块的旋转方向，默认为0。
   * @param options 其他选项，例如 `{ isHollow: true }` 来创建空心圆柱。
   * @returns 一个包含圆柱体的全新 `TerrainSchematic` 实例。
   */
  public static fromCylinder(
    radius: number,
    height: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: CylinderOptions = {}
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createCylinder(
      schematic,
      radius,
      height,
      voxelId,
      voxelRot,
      options
    );
  }

  /**
   * 根据给定的参数创建一个金字塔蓝图。
   * @param baseSize 金字塔底座的边长。
   * @param height 金字塔的高度。
   * @param voxelId 用于构成金字塔的方块ID。
   * @param voxelRot 金字塔方块的旋转方向，默认为0。
   * @param options 其他选项，例如 `{ isHollow: true }` 来创建空心金字塔。
   * @returns 一个包含金字塔的全新 `TerrainSchematic` 实例。
   */
  public static fromPyramid(
    baseSize: number,
    height: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: PyramidOptions = {}
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createPyramid(
      schematic,
      baseSize,
      height,
      voxelId,
      voxelRot,
      options
    );
  }

  /**
   * 根据给定的尺寸创建一个长方体蓝图。
   * @param size 长方体的尺寸 (x, y, z)。
   * @param voxelId 用于构成形状的方块ID。
   * @param voxelRot 方块的旋转方向，默认为0。
   * @param options 其他选项，例如 `{ isHollow: true }` 来创建空心长方体。
   * @returns 一个包含长方体的全新 `TerrainSchematic` 实例。
   */
  public static fromCuboid(
    size: GameVector3,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: CuboidOptions = {}
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createCuboid(schematic, size, voxelId, voxelRot, options);
  }

  /**
   * 根据给定的参数创建一个圆环体（甜甜圈）蓝图。
   * @param majorRadius 圆环的主半径（从圆心到管道中心的距离）。
   * @param minorRadius 圆环的次半径（管道的半径）。
   * @param voxelId 用于构成形状的方块ID。
   * @param voxelRot 方块的旋转方向，默认为0。
   * @returns 一个包含圆环体的全新 `TerrainSchematic` 实例。
   */
  public static fromTorus(
    majorRadius: number,
    minorRadius: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createTorus(schematic, majorRadius, minorRadius, voxelId, voxelRot);
  }

  /**
   * 根据给定的参数创建一个管道（空心圆柱体）蓝图。
   * @param height 管道的高度。
   * @param radius 管道的外半径。
   * @param thickness 管道的壁厚。
   * @param voxelId 用于构成形状的方块ID。
   * @param voxelRot 方块的旋转方向，默认为0。
   * @returns 一个包含管道的全新 `TerrainSchematic` 实例。
   */
  public static fromPipe(
    height: number,
    radius: number,
    thickness: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createPipe(schematic, height, radius, thickness, voxelId, voxelRot);
  }

  /**
   * 根据给定的参数创建一个胶囊体蓝图。
   * @param height 胶囊体中间圆柱部分的高度。
   * @param radius 胶囊体的半径。
   * @param voxelId 用于构成形状的方块ID。
   * @param voxelRot 方块的旋转方向，默认为0。
   * @returns 一个包含胶囊体的全新 `TerrainSchematic` 实例。
   */
  public static fromCapsule(
    height: number,
    radius: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createCapsule(schematic, height, radius, voxelId, voxelRot);
  }

  /**
   * 根据给定的参数创建一个圆锥体蓝图。
   * @param radius 圆锥底部的半径。
   * @param height 圆锥的高度。
   * @param voxelId 用于构成圆锥的方块ID。
   * @param voxelRot 圆锥方块的旋转方向，默认为0。
   * @param options 其他选项，例如 `{ isHollow: true }` 来创建空心圆锥。
   * @returns 一个包含圆锥体的全新 `TerrainSchematic` 实例。
   */
  public static fromCone(
    radius: number,
    height: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: ConeOptions = {}
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createCone(schematic, radius, height, voxelId, voxelRot, options);
  }

  /**
   * 根据给定的参数创建一个棱柱蓝图。
   * @param sides 棱柱底面的边数 (例如 3=三棱柱, 6=六棱柱)。
   * @param radius 棱柱底面外接圆的半径。
   * @param height 棱柱的高度。
   * @param voxelId 用于构成棱柱的方块ID。
   * @param voxelRot 棱柱方块的旋转方向，默认为0。
   * @param options 其他选项，例如 `{ isHollow: true }` 来创建空心棱柱。
   * @returns 一个包含棱柱的全新 `TerrainSchematic` 实例。
   */
  public static fromPrism(
    sides: number,
    radius: number,
    height: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: PrismOptions = {}
  ): TerrainSchematic {
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    return createPrism(
      schematic,
      sides,
      radius,
      height,
      voxelId,
      voxelRot,
      options
    );
  }

  /**
   * 沿路径放置一个“图章”蓝图来创建一个新的蓝图。
   * @param stamp 要沿路径放置的 `TerrainSchematic` 实例。
   * @param path 定义路径的 `GameVector3` 点数组。
   * @param options 配置选项。
   * @returns 一个包含最终组合形状的全新 `TerrainSchematic` 实例。
   */
  public static fromPath(
    stamp: TerrainSchematic,
    path: GameVector3[],
    options: FromPathOptions = {}
  ): TerrainSchematic {
    const {
      useBezier = false,
      bezierSampleCount = 20,
      step = 1,
      alignToPath = true,
    } = options;

    let finalPath = path;
    if (useBezier) {
      finalPath = generateCatmullRomPath(path, bezierSampleCount);
    }

    const transforms = generateStampTransformsOnPath(
      finalPath,
      step,
      alignToPath
    );

    const finalSchematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;
    finalSchematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [],
    };
    finalSchematic.schematicBlocks = [];
    finalSchematic.origin = new GameVector3(0, 0, 0);

    for (const transform of transforms) {
      const stampCopy = stamp.clone();
      if (alignToPath) {
        stampCopy.rotate("y", transform.rotation.y);
      }
      // 我们需要将点的位置从世界坐标转换为相对于最终蓝图原点的位置
      // 但由于我们最后会进行归一化，所以现在可以直接使用
      finalSchematic.add(stampCopy, transform.position);
    }

    normalizeAndUpdateBounds(finalSchematic);
    return finalSchematic;
  }

  /**
   * 沿着定义的一系列点创建一道墙。
   * 这是一个便捷方法，它内部会调用 `fromPath`。
   * @param path `GameVector3` 点的数组，定义了墙的路径。
   * @param height 墙的高度。
   * @param thickness 墙的厚度。
   * @param voxelId 用于构成墙的方块ID。
   * @param voxelRot 方块的旋转方向，默认为0。
   * @param options `fromPath` 的高级选项，如 `useBezier`。
   * @returns 一个包含墙体的全新 `TerrainSchematic` 实例。
   */
  public static fromPathWall(
    path: GameVector3[],
    height: number,
    thickness: number,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    options: FromPathWallOptions = {}
  ): TerrainSchematic {
    // 创建一个代表墙体横截面的小蓝图作为图章
    const wallSection = TerrainSchematic.fromCuboid(
      new GameVector3(thickness, height, 1),
      voxelId,
      voxelRot
    );

    // 调用 fromPath, step为1以创建连续的墙体, 并且总是对齐路径
    const combinedOptions = {
      ...options,
      step: options.step ?? 1,
      alignToPath: true,
    };

    return TerrainSchematic.fromPath(wallSection, path, combinedOptions);
  }

  /**
   * 根据给定的文本生成一个3D文字的蓝图。
   * @param text 要生成的字符串（非中文）。
   * @param voxelId 用于构成文字的方块ID。
   * @param voxelRot 文字方块的旋转方向，默认为0。
   * @param fontHeight 文字的高度，默认为5。
   * @returns 一个包含3D文字的全新 `TerrainSchematic` 实例。
   */
  public static fromText(
    text: string,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0,
    fontHeight: number = 5
  ): TerrainSchematic {
    // 使用 Object.create 创建一个空实例，避免触发构造函数
    const schematic = Object.create(
      TerrainSchematic.prototype
    ) as TerrainSchematic;

    // 初始化数据
    schematic.data = {
      bounds: new GameBounds3(
        new GameVector3(0, 0, 0),
        new GameVector3(0, 0, 0)
      ),
      palette: [voxelId, voxelRot],
    };
    schematic.schematicBlocks = [];
    schematic.origin = new GameVector3(0, 0, 0);

    let cursorX = 0;

    for (const char of text) {
      const charPattern = FONT_5X5[char];
      if (!charPattern || charPattern.length === 0) {
        cursorX += FONT_5X5_SPACING; // 如果字符不存在或为空，则视为空格
        continue;
      }

      const fontDataHeight = charPattern.length;
      const charWidth = charPattern[0] ? charPattern[0].length : 0;
      if (charWidth === 0) {
        cursorX += FONT_5X5_SPACING;
        continue;
      }

      for (let y = 0; y < fontHeight; y++) {
        // 使用最近邻插值从源字体数据中采样垂直像素
        // 这样可以正确地拉伸或压缩字体以匹配所需的 fontHeight
        const sourceY = Math.floor(y * (fontDataHeight / fontHeight));

        for (let x = 0; x < charWidth; x++) {
          // 检查 sourceY 是否在 charPattern 的有效范围内
          if (charPattern[sourceY] && charPattern[sourceY][x] === "1") {
            schematic.schematicBlocks.push({
              x: cursorX + x,
              y: fontHeight - 1 - y, // Y轴反转，因为我们从上到下绘制
              z: 0,
              p: 0, // 调色板中只有一种方块
            });
          }
        }
      }
      cursorX += charWidth + FONT_5X5_SPACING;
    }

    // 更新最终的边界框
    if (schematic.schematicBlocks.length > 0) {
      const size = getDimensions(schematic); // 调用实例方法来计算
      schematic.data.bounds = new GameBounds3(
        new GameVector3(0, 0, 0),
        size.sub(new GameVector3(1, 1, 1))
      );
    }

    return schematic;
  }

  /**
   * 导出当前蓝图的压缩数据格式。
   * 这个数据可以被序列化（例如，保存为JSON），以便之后通过 `TerrainSchematic.fromData()` 方法重新加载。
   * @returns {CompressedTerrainData} 包含边界、调色板和图层字符串的压缩数据对象。
   */
  public getData(): CompressedTerrainData {
    return getData(this);
  }

  /**
   * 从游戏世界中捕获一个区域的地形，并更新当前蓝图实例。
   * @param {GameBounds3} bounds 要捕获的地形区域。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public export(bounds: GameBounds3): TerrainSchematic {
    return exportFromWorld(this, bounds);
  }

  /**
   * 将当前蓝图同步地导入到游戏世界中。
   * @param {GameVector3} [position] 导入位置的世界坐标。如果未提供，则使用蓝图的原始原点。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public import(position?: GameVector3): TerrainSchematic {
    return importToWorld(this, position);
  }

  /**
   * 将当前蓝图异步地导入到游戏世界中，以避免阻塞游戏主线程。
   * @param {GameVector3} [position] 导入位置的世界坐标。如果未提供，则使用蓝图的原始原点。
   * @param {number} [blocksPerTick=200] 每游戏刻处理的方块数量。
   * @returns {Promise<TerrainSchematic>} 一个在导入完成时解析的Promise，返回当前实例。
   */
  public importAsync(
    position?: GameVector3,
    blocksPerTick: number = 200
  ): Promise<TerrainSchematic> {
    return importToWorldAsync(this, position, blocksPerTick);
  }

  /**
   * 获取蓝图的尺寸（宽度、高度、深度）。
   * @returns {GameVector3} 一个包含x, y, z尺寸的向量。
   */
  public getDimensions(): GameVector3 {
    return getDimensions(this);
  }

  /**
   * 计算构建此蓝图所需的各种材料的数量。
   * @returns {Map<voxelId, number>} 一个Map，键是方块ID，值是所需的数量。
   */
  public getMaterialCost(): Map<voxelId, number> {
    return getMaterialCost(this);
  }

  /**
   * 围绕指定的轴心旋转蓝图。
   * @param {'x' | 'y' | 'z'} axis 旋转轴。
   * @param {number} angle 旋转任意角度。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public rotate(axis: "x" | "y" | "z", angle: number): TerrainSchematic {
    return rotate(this, axis, angle);
  }

  /**
   * 围绕指定的轴心缩放蓝图。
   * @param {GameVector3} scale 包含x, y, z缩放因子的向量。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public scale(scale: GameVector3): TerrainSchematic {
    return scaleOperation(this, scale);
  }

  /**
   * 沿X或Z轴翻转蓝图。
   * @param {'x' | 'z'} axis 翻转轴。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public flip(axis: "x" | "z"): TerrainSchematic {
    return flip(this, axis);
  }

  /**
   * 沿指定轴镜像蓝图。
   * @param {'x' | 'y' | 'z'} axis 镜像轴。
   * @param {boolean} [keepPositiveSide=false] 如果为true，则保留正半轴的部分并将其镜像到负半轴；否则，保留负半轴的部分。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public mirror(
    axis: "x" | "y" | "z",
    keepPositiveSide: boolean = false
  ): TerrainSchematic {
    return mirror(this, axis, keepPositiveSide);
  }

  /**
   * 根据提供的替换表，替换蓝图中的特定方块。
   * @param {ReplacementMap} replacementMap 一个定义了如何替换方块的Map。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public replaceBlocks(replacementMap: ReplacementMap): TerrainSchematic {
    return replaceBlocks(this, replacementMap);
  }

  /**
   * 根据一个带权重的模式来替换方块，可以用来创建更自然的纹理混合。
   * @param {PatternMap} patternMap 一个定义了替换规则的Map。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public replaceByPattern(patternMap: PatternMap): TerrainSchematic {
    return replaceByPattern(this, patternMap);
  }

  /**
   * 将蓝图中的所有方块（可选择排除某些类型）替换为指定的单一类型方块。
   * @param {voxelId} [voxelId=0] 新方块的ID。
   * @param {voxelRotation} [voxelRot=0] 新方块的旋转。
   * @param {voxelId[]} [excludeIds=[]] 要在替换中排除的方块ID列表。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public replaceAllBlocks(
    voxelId: voxelId = 0,
    voxelRot: voxelRotation = 0,
    excludeIds: voxelId[] = []
  ): TerrainSchematic {
    return replaceAllBlocks(this, voxelId, voxelRot, excludeIds);
  }

  /**
   * 创建蓝图的线框表示。
   * @param {number} [thickness=1] 线框的厚度。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public wireFrame(thickness: number = 1): TerrainSchematic {
    return wireFrame(this, thickness);
  }

  /**
   * 随机移除一定百分比的方块，以模拟腐朽或风化效果。
   * @param {number} percentage 要移除的方块百分比 (0-1)。
   * @param {boolean} [applyGravity=true] 如果为true，则使悬空的方块下落。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public decay(
    percentage: number,
    applyGravity: boolean = true
  ): TerrainSchematic {
    return decay(this, percentage, applyGravity);
  }

  /**
   * 在X, Y, Z方向上堆叠蓝图的副本。
   * @param {GameVector3} counts 包含在每个轴上堆叠次数的向量。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public stack(counts: GameVector3): TerrainSchematic {
    return stack(this, counts);
  }

  /**
   * 沿指定轴，用一个方块ID列表渐变地替换现有方块。
   * @param {'x' | 'y' | 'z'} axis 渐变轴。
   * @param {voxelId[]} voxelIds 用于渐变的方块ID数组。
   * @param {boolean} [dither=true] 是否应用抖动以创建更平滑的过渡。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public gradientReplace(
    axis: "x" | "y" | "z",
    voxelIds: voxelId[],
    dither: boolean = true
  ): TerrainSchematic {
    return gradientReplace(this, axis, voxelIds, dither);
  }

  /**
   * 将另一个蓝图与当前蓝图合并（并集）。
   * @param {TerrainSchematic} other 要添加的另一个蓝图。
   * @param {GameVector3} [position=new GameVector3(0, 0, 0)] 另一个蓝图相对于当前蓝图的放置位置。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public add(
    other: TerrainSchematic,
    position: GameVector3 = new GameVector3(0, 0, 0)
  ): TerrainSchematic {
    return add(this, other, position);
  }

  /**
   * 从当前蓝图中减去另一个蓝图（差集）。
   * @param {TerrainSchematic} other 要减去的另一个蓝图。
   * @param {GameVector3} [position=new GameVector3(0, 0, 0)] 另一个蓝图相对于当前蓝图的放置位置。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public subtract(
    other: TerrainSchematic,
    position: GameVector3 = new GameVector3(0, 0, 0)
  ): TerrainSchematic {
    return subtract(this, other, position);
  }

  /**
   * 计算当前蓝图与另一个蓝图的交集。
   * @param {TerrainSchematic} other 用于计算交集的另一个蓝图。
   * @param {GameVector3} [position=new GameVector3(0, 0, 0)] 另一个蓝图相对于当前蓝图的放置位置。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public intersect(
    other: TerrainSchematic,
    position: GameVector3 = new GameVector3(0, 0, 0)
  ): TerrainSchematic {
    return intersect(this, other, position);
  }

  /**
   * 使蓝图中的表面变厚。
   * @param {number} [thickness=1] 厚度。
   * @param {voxelId} voxelId 用于增厚的方块ID。
   * @param {voxelRotation} [voxelRot=0] 用于增厚的方块旋转。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public thicken(
    thickness: number = 1,
    voxelId: voxelId,
    voxelRot: voxelRotation = 0
  ): TerrainSchematic {
    return thicken(this, thickness, voxelId, voxelRot);
  }

  /**
   * 使用元胞自动机算法平滑蓝图的地形。
   * @param {SmoothOptions} [options] 平滑算法的选项。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public smooth(options?: SmoothOptions): TerrainSchematic {
    return smooth(this, options);
  }

  /**
   * 锐化蓝图的地形特征。
   * @param {SharpenOptions} [options] 锐化算法的选项。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public sharpen(options?: SharpenOptions): TerrainSchematic {
    return sharpen(this, options);
  }

  /**
   * 对地形进行液压侵蚀模拟，创造更自然的沟壑和沉积物外观。
   * @param options 侵蚀算法的详细参数。
   * @returns 返回当前实例，以支持链式调用。
   */
  public erode(options?: Partial<ErosionOptions>): TerrainSchematic {
    return erode(this, options);
  }

  /**
   * 将实心结构转换为空心外壳。
   * @param thickness 外壳的厚度，默认为1。
   * @returns `this`，允许链式调用。
   */
  public shell(thickness: number = 1): TerrainSchematic {
    return shell(this, thickness);
  }

  /**
   * 在当前蓝图的表面上克隆另一个小蓝图（“印章”）。
   * @param {TerrainSchematic} stamp 要克隆的“印章”蓝图。
   * @param {CloneToSurfaceOptions} [options] 克隆选项。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public cloneToSurface(
    stamp: TerrainSchematic,
    options: CloneToSurfaceOptions = {}
  ): TerrainSchematic {
    return cloneToSurface(this, stamp, options);
  }

  /**
   * 设置用于旋转和缩放操作的自定义轴心点。
   * @param {GameVector3} pivot 轴心点的局部坐标。
   * @param {boolean} [isGlobal=false] 如果为true，则提供的pivot是世界坐标，否则是相对于蓝图边界的局部坐标。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public setPivot(
    pivot: GameVector3,
    isGlobal: boolean = false
  ): TerrainSchematic {
    return setPivot(this, pivot, isGlobal);
  }

  /**
   * 清除自定义轴心点，恢复使用几何中心作为轴心。
   * @returns {TerrainSchematic} 返回当前实例，以支持链式调用。
   */
  public clearPivot(): TerrainSchematic {
    return clearPivot(this);
  }

  /**
   * 生成一个控制台命令，用于在指定位置创建此蓝图，并将该命令复制到玩家的剪贴板。
   * @param {GameVector3} position 放置蓝图的世界坐标。
   * @param {GamePlayerEntity} entity 触发此操作的玩家实体。
   * @returns {Promise<boolean>} 如果复制成功，则返回true。
   */
  public async copyConsoleCommand(
    position: GameVector3,
    entity: GamePlayerEntity
  ): Promise<boolean> {
    return copyConsoleCommand(this, position, entity);
  }

  /**
   * 将蓝图数据作为JSON字符串复制到玩家的剪贴板。
   * @param {GamePlayerEntity} entity 触发此操作的玩家实体。
   * @returns {Promise<boolean>} 如果复制成功，则返回true。
   */
  public async copyJSON(entity: GamePlayerEntity): Promise<boolean> {
    return copyJSON(this, entity);
  }
}
